package forwarder

import (
	"fmt"
	"io"
	"net"
	"sync"
	"time"

	"nettools/shared/models"
	"nettools/shared/utils"
)

// ExternalClient 外网客户端
type ExternalClient struct {
	config *models.ClientConfig

	// 监听器管理
	listeners    map[string]net.Listener // 本地监听器
	listenersMux sync.RWMutex

	// 会话管理
	sessions    map[string]*ProxySession // 代理会话
	sessionsMux sync.RWMutex

	// 控制通道
	stopChan chan struct{}
	wg       sync.WaitGroup
	running  bool
	mu       sync.RWMutex
}

// ProxySession 代理会话
type ProxySession struct {
	ID         string
	LocalConn  net.Conn // 本地客户端连接
	ServerConn net.Conn // 到服务器的连接
	Service    string   // 服务名称
	CreatedAt  time.Time
}

// NewExternalClient 创建新的外网客户端
func NewExternalClient(config *models.ClientConfig) *ExternalClient {
	return &ExternalClient{
		config:    config,
		listeners: make(map[string]net.Listener),
		sessions:  make(map[string]*ProxySession),
		stopChan:  make(chan struct{}),
	}
}

// Start 启动外网客户端
func (ec *ExternalClient) Start() error {
	utils.Info("🚀 启动外网客户端...")
	utils.Info("客户端ID: %s", ec.config.ClientID)
	utils.Info("服务器地址: %s:%d", ec.config.ServerAddr, ec.config.ServerPort)

	// 启动所有本地监听器
	if err := ec.startListeners(); err != nil {
		return fmt.Errorf("启动监听器失败: %w", err)
	}

	ec.mu.Lock()
	ec.running = true
	ec.mu.Unlock()

	utils.Info("✅ 外网客户端启动成功!")
	return nil
}

// startListeners 启动所有监听器
func (ec *ExternalClient) startListeners() error {
	utils.Info("启动本地监听器...")

	for _, service := range ec.config.Services {
		if err := ec.startServiceListener(service); err != nil {
			return fmt.Errorf("启动服务 %s 监听器失败: %w", service.Name, err)
		}
	}

	utils.Info("✅ 所有监听器启动成功")
	return nil
}

// startServiceListener 启动服务监听器
func (ec *ExternalClient) startServiceListener(service models.Service) error {
	localAddr := fmt.Sprintf("%s:%d", ec.config.LocalHost, service.LocalPort)

	listener, err := net.Listen("tcp", localAddr)
	if err != nil {
		return fmt.Errorf("监听地址 %s 失败: %w", localAddr, err)
	}

	ec.listenersMux.Lock()
	ec.listeners[service.Name] = listener
	ec.listenersMux.Unlock()

	utils.Info("监听服务: %s (本地端口: %d -> 服务器端口: %d)",
		service.Name, service.LocalPort, service.ServerPort)

	// 启动监听协程
	ec.wg.Add(1)
	go ec.handleServiceListener(service, listener)

	return nil
}

// handleServiceListener 处理服务监听器
func (ec *ExternalClient) handleServiceListener(service models.Service, listener net.Listener) {
	defer ec.wg.Done()
	defer listener.Close()

	for {
		select {
		case <-ec.stopChan:
			return
		default:
			conn, err := listener.Accept()
			if err != nil {
				select {
				case <-ec.stopChan:
					return
				default:
					utils.Error("接受连接失败: %v", err)
					continue
				}
			}

			// 处理新的本地连接
			ec.wg.Add(1)
			go ec.handleLocalConnection(service, conn)
		}
	}
}

// handleLocalConnection 处理本地连接
func (ec *ExternalClient) handleLocalConnection(service models.Service, localConn net.Conn) {
	defer ec.wg.Done()
	defer localConn.Close()

	utils.Info("新的本地连接: %s -> 服务 %s", localConn.RemoteAddr(), service.Name)

	// 连接到服务器（带重试机制）
	serverConn, err := ec.connectToServerWithRetry(service)
	if err != nil {
		utils.Error("连接服务器失败: %v", err)
		return
	}
	defer serverConn.Close()

	utils.Info("✅ 已连接到服务器端口: %d", service.ServerPort)

	// 创建代理会话
	sessionID := fmt.Sprintf("%s-%d", service.Name, time.Now().UnixNano())
	session := &ProxySession{
		ID:         sessionID,
		LocalConn:  localConn,
		ServerConn: serverConn,
		Service:    service.Name,
		CreatedAt:  time.Now(),
	}

	ec.sessionsMux.Lock()
	ec.sessions[sessionID] = session
	ec.sessionsMux.Unlock()

	utils.Info("创建代理会话: %s", sessionID)

	// 启动双向数据转发
	ec.startBidirectionalForward(session)
}

// connectToServerWithRetry 带重试机制的服务器连接
func (ec *ExternalClient) connectToServerWithRetry(service models.Service) (net.Conn, error) {
	serverAddr := fmt.Sprintf("%s:%d", ec.config.ServerAddr, service.ServerPort)
	maxAttempts := 3

	for attempt := 1; attempt <= maxAttempts; attempt++ {
		utils.Debug("尝试连接服务器: %s (尝试 %d/%d)", serverAddr, attempt, maxAttempts)

		serverConn, err := net.DialTimeout("tcp", serverAddr, 10*time.Second)
		if err == nil {
			return serverConn, nil
		}

		utils.Error("连接服务器失败 (尝试 %d/%d): %v", attempt, maxAttempts, err)

		// 如果不是最后一次尝试，等待后重试
		if attempt < maxAttempts {
			retryDelay := time.Duration(attempt) * time.Second
			utils.Info("⏳ %d秒后重试...", int(retryDelay.Seconds()))

			select {
			case <-time.After(retryDelay):
				continue
			case <-ec.stopChan:
				return nil, fmt.Errorf("客户端已停止")
			}
		}
	}

	return nil, fmt.Errorf("连接服务器失败，已达到最大重试次数 (%d)", maxAttempts)
}

// startBidirectionalForward 启动双向数据转发
func (ec *ExternalClient) startBidirectionalForward(session *ProxySession) {
	defer func() {
		// 清理会话
		ec.sessionsMux.Lock()
		delete(ec.sessions, session.ID)
		ec.sessionsMux.Unlock()
		utils.Info("代理会话结束: %s", session.ID)
	}()

	// 创建错误通道用于任一方向转发失败时通知
	errChan := make(chan error, 2)

	// 启动本地到服务器的转发
	go func() {
		_, err := io.Copy(session.ServerConn, session.LocalConn)
		errChan <- err
	}()

	// 启动服务器到本地的转发
	go func() {
		_, err := io.Copy(session.LocalConn, session.ServerConn)
		errChan <- err
	}()

	// 等待任一方向转发结束
	select {
	case err := <-errChan:
		if err != nil && err != io.EOF {
			utils.Debug("数据转发结束: %v", err)
		}
	case <-ec.stopChan:
		return
	}
}

// GetSessionCount 获取会话数量
func (ec *ExternalClient) GetSessionCount() int {
	ec.sessionsMux.RLock()
	defer ec.sessionsMux.RUnlock()
	return len(ec.sessions)
}

// GetListenerCount 获取监听器数量
func (ec *ExternalClient) GetListenerCount() int {
	ec.listenersMux.RLock()
	defer ec.listenersMux.RUnlock()
	return len(ec.listeners)
}

// GetStats 获取统计信息
func (ec *ExternalClient) GetStats() map[string]interface{} {
	stats := make(map[string]interface{})

	stats["sessions"] = ec.GetSessionCount()
	stats["listeners"] = ec.GetListenerCount()
	stats["running"] = ec.isRunning()
	stats["services"] = len(ec.config.Services)

	// 添加每个服务的详细信息
	serviceStats := make(map[string]interface{})
	for _, service := range ec.config.Services {
		serviceStats[service.Name] = map[string]interface{}{
			"local_port":  service.LocalPort,
			"server_port": service.ServerPort,
			"protocol":    service.Protocol,
		}
	}
	stats["service_details"] = serviceStats

	return stats
}

// isRunning 检查是否正在运行
func (ec *ExternalClient) isRunning() bool {
	ec.mu.RLock()
	defer ec.mu.RUnlock()
	return ec.running
}

// Stop 停止外网客户端
func (ec *ExternalClient) Stop() error {
	utils.Info("🛑 正在停止外网客户端...")

	ec.mu.Lock()
	ec.running = false
	ec.mu.Unlock()

	// 发送停止信号
	close(ec.stopChan)

	// 关闭所有监听器
	ec.listenersMux.Lock()
	for name, listener := range ec.listeners {
		utils.Info("关闭监听器: %s", name)
		listener.Close()
	}
	ec.listenersMux.Unlock()

	// 关闭所有会话
	ec.sessionsMux.Lock()
	for _, session := range ec.sessions {
		session.LocalConn.Close()
		session.ServerConn.Close()
	}
	ec.sessionsMux.Unlock()

	// 等待所有协程结束
	ec.wg.Wait()

	utils.Info("✅ 外网客户端已停止")
	return nil
}
